from genericpath import isfile
from importlib.abc import SourceLoader
from importlib.util import source_hash
import json
import os
from socket import socket
import subprocess
import tarfile
import tty
import docker
from io import BytesIO

from pymysql import NULL

class DockerProxy(object):

    def __init__(self) -> None:
        self._docker = docker.DockerClient(base_url="unix://var/run/docker.sock",timeout=10)

    def get_version(self):
        """
        get docker version.
        
        :param param1: this is a first param
        :returns: this is a description of what is returned
        :raises keyError: raises an exception
        """
        return self._docker.version()

    def get_image_list(self) -> list:
        """
        get docker images
        """
        images = self._docker.api.images()
        res = []

        for image in images:
            image_id = image["Id"].lstrip("sha256")
            for image_name in image["RepoTags"]:
                res.append({
                    'image_id': image_id,
                    'image_name': image_name
                })
        return res
    
    def get_container_list(self) -> list:
        """
        get docker container
        """
        containers = self._docker.api.containers(all = True)
        res = []
        for container in containers:
            # print(container)
            container_name = container["Names"][0].lstrip("//")
            res.append({
                'container_id': container["Id"],
                'container_name': container_name,
                'status': container["State"]
            })
        return res

    def get_container_info(self, container_id = "", container_name = "") -> object:
        """
        get container info
        """
        info = {}
        try:
            if container_id != "":
                info = self._docker.api.inspect_container(container_id)
            elif container_name != "":
                info = self._docker.api.inspect_container(container_name)
        except:
            pass
        return info


    def create_container(self, image_name, conf = {}):
        container = self._docker.api.create_container(image_name, "bash", detach=True, stdin_open= True, tty=True)
        self.start_container(container_id=container["Id"])
        return container["Id"]
    
    def start_container(self, container_id):
        info = self.get_container_info(container_id=container_id)
        print(info["State"])
        if info == {}:
            return False
        if info["State"]["Running"] == True:
            print("running")
            return True
        else:
            print("no running")
            res = self._docker.api.start(container = info["Id"])
            return res == None

    def run_container_command(self, container_id, commands, work_dir=None, user = None):
        container = self._docker.containers.get(container_id=container_id)
        outs = ""
        for command in commands:
            container_output = container.exec_run(command,workdir=work_dir)
            out = str(container_output.output, 'utf-8').replace("\\n", "\n")
            outs += out
        return outs
    def run_container_command_stream(self, container_id, command, work_dir=None, user = None):
        container = self._docker.containers.get(container_id=container_id)
        container_output = container.exec_run(command,workdir=work_dir,socket=True,stream=True,user=user)
        return container_output.output

    def start_container_command_test(self, container_id, commands, work_dir=None, user = None):
        container = self._docker.containers.get(container_id=container_id)
        container_output = container.exec_run(commands,workdir=work_dir)
        out = str(container_output.output, 'utf-8').replace("\\n", "\n")
        return out
    
    def copy_to_container(self, container_id, source_path, to_path):
        tar = self.add_tar(source_path)
        return self._docker.api.put_archive(container=container_id,path = to_path,data = tar)

    def copy_from_container(self, container_id, from_path, dst_path):
        pw_tarstream = BytesIO()
        bits, _ = self._docker.api.get_archive(container_id, from_path)
        for trunk in bits:
            pw_tarstream.write(trunk)
        pw_tarstream.seek(0)
        tar = tarfile.open(fileobj = pw_tarstream)
        res = tar.extractall(path = dst_path)
        return res == None
    
    def stop_container(self, container_id):
        return self._docker.api.stop(container = container_id) == None

    def destory_container(self, container_id):
        info = self.get_container_info(container_id=container_id)
        if info == {}:
            return True
        if info["State"]["Running"] == True:
            self.stop_container(container_id)
        res = self._docker.api.remove_container(container_id)
        return res == None

    def pull_image(self, image_name):
        self._docker.api.pull(repository = image_name)

    @staticmethod
    def add_tar(path_dir) -> bytes:
        if os.path.exists(path = path_dir):
            pw_tarstream = BytesIO()
            pw_tar = tarfile.TarFile(fileobj=pw_tarstream, mode='w')
            pw_tar.add(name = path_dir, arcname=os.path.basename(path_dir))
            pw_tar.close()
            pw_tarstream.seek(0)
            return pw_tarstream
        
        return NULL